package com.rain.cy.business.service;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.rain.cy.business.constant.CommonConstant;
import com.rain.cy.business.converter.UserProcessDataConverter;
import com.rain.cy.business.mapper.UserProcessDataMapper;
import com.rain.cy.business.model.dto.CountDataDTO;
import com.rain.cy.business.model.dto.UserProcessDataDTO;
import com.rain.cy.business.model.entity.UserEntity;
import com.rain.cy.business.model.entity.UserProcessDataEntity;
import com.rain.cy.business.model.json.ProcessFiveOfDataJson;
import com.rain.cy.business.model.json.ProcessFourOfDataJson;
import com.rain.cy.business.model.vo.ItemRecordVO;
import com.rain.cy.framework.entity.BaseEntity;
import com.rain.cy.framework.entity.impl.BaseServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author yuchen
 * @since 2021-10-02
 */
@Service
@Slf4j
public class UserProcessDataService extends BaseServiceImpl<UserProcessDataMapper, UserProcessDataEntity> {

    @Autowired
    private UserProcessDataService userProcessDataService;

    @Autowired
    private UserService userService;

    /**
     * 保存进程数据 确保 每天只有一条进程数据
     *
     * @param userProcessDataEntity 用户进程数据
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrUpdateHandler(UserProcessDataEntity userProcessDataEntity) {
        UserEntity userEntity = userService.getById(userProcessDataEntity.getUserId());
        if (userProcessDataEntity.getId() == null) {
            UserProcessDataEntity one = userProcessDataService.lambdaQuery().eq(UserProcessDataEntity::getUserId, userProcessDataEntity.getUserId())
                    .eq(UserProcessDataEntity::getProcessId, userProcessDataEntity.getProcessId())
                    .eq(UserProcessDataEntity::getCreateDay, DateUtil.today()).last("limit 1").one();
            if (one != null) {
                userProcessDataEntity.setId(one.getId());
                userProcessDataEntity.setCreateDay(one.getCreateDay());
            }
        }
        if (StringUtils.isEmpty(userProcessDataEntity.getCreateDay())){
            userProcessDataEntity.setCreateDay(DateUtil.today());
        }
        if (StringUtils.isNotEmpty(userProcessDataEntity.getProcessData())){
            JSON parse = JSONUtil.parse(userProcessDataEntity.getProcessData());
            userProcessDataEntity.setProcessData(JSONUtil.toJsonStr(parse));
        }
        userProcessDataEntity.setDoctorUserId(userEntity.getDoctorId());
        boolean saveOrUpdate = userProcessDataService.saveOrUpdate(userProcessDataEntity);
        if (!saveOrUpdate) {
            return false;
        }
        UserProcessDataDTO userProcessDataDTO = Optional.of(userProcessDataEntity).map(UserProcessDataDTO::from)
                .map(UserProcessDataConverter::initBaseProcessDataJson).orElse(new UserProcessDataDTO());
        UserProcessDataConverter.HANDLER_MAP.get(userProcessDataDTO.getProcessId()).handler(userProcessDataDTO);
        return true;
    }


    public List<UserProcessDataDTO> queryUserProcessData(Integer userId, String processId) {
        return queryUserProcessData(userId, processId, false);
    }

    public List<UserProcessDataDTO> queryUserProcessData(Integer userId, String processId, boolean isLimit) {
        List<UserProcessDataEntity> processDataEntities = lambdaQuery()
                .eq(UserProcessDataEntity::getProcessId, processId)
                .eq(UserProcessDataEntity::getUserId, userId)
                .orderByDesc(BaseEntity::getCreateTime)
                .last(isLimit, "limit 10")
                .list();
        if (CollectionUtil.isEmpty(processDataEntities)) {
            UserProcessDataDTO userProcessDataDTO = new UserProcessDataDTO();
            userProcessDataDTO.setProcessId(processId);
            userProcessDataDTO.setCreateDay(DateUtil.today());
            userProcessDataDTO.setUserId(userId);
            UserProcessDataConverter.HANDLER_MAP.get(processId).queryHandler(userProcessDataDTO);
            return Collections.singletonList(userProcessDataDTO);
        }
        return processDataEntities.stream().map(UserProcessDataDTO::from)
                .map(UserProcessDataConverter::initBaseProcessDataJson)
                .collect(Collectors.toList());
    }


    public CountDataDTO buildFourCountData(Integer userId) {
        List<UserProcessDataDTO> userProcessDataDTOList = queryUserProcessData(userId, CommonConstant.PROCESS_ID_FOUR);
        CountDataDTO countDataDTO = CountDataDTO.of();
        int sum = 0;
        countDataDTO.appendLegend("不良反应记录");
        countDataDTO.appendLegend("耐药度记录");
        if (CollectionUtil.isEmpty(userProcessDataDTOList)) {
            countDataDTO.setScoreAvg(0);
            return countDataDTO;
        }
        for (UserProcessDataDTO userProcessDataDTO : userProcessDataDTOList) {
            if (!(userProcessDataDTO.getBaseProcessDataJson() instanceof ProcessFourOfDataJson)) {
                continue;
            }
            ProcessFourOfDataJson processDataJson = (ProcessFourOfDataJson) userProcessDataDTO.getBaseProcessDataJson();
            countDataDTO.getXTypeList().add(userProcessDataDTO.getCreateDay());
            int score1 = Optional.ofNullable(processDataJson).map(ProcessFourOfDataJson::getRecordOfBadReaction).map(ItemRecordVO::getScore).orElse(0);
            int score2 = Optional.ofNullable(processDataJson).map(ProcessFourOfDataJson::getRecordOfDrugResistance).map(ItemRecordVO::getScore).orElse(0);
            countDataDTO.getSeriesList().get(0).getData().add(score1);
            countDataDTO.getSeriesList().get(1).getData().add(score2);
            sum += score1 + score2;
        }
        int nums = countDataDTO.getSeriesList().size() * countDataDTO.getSeriesList().get(0).getData().size();
        int scoreAvg = nums == 0 ? 0 : sum / nums;
        countDataDTO.setScoreAvg(scoreAvg);
        return countDataDTO;
    }

    public CountDataDTO buildFiveCountData(Integer userId) {
        List<UserProcessDataDTO> userProcessDataDTOList = queryUserProcessData(userId, CommonConstant.PROCESS_ID_FIVE);
        CountDataDTO countDataDTO = CountDataDTO.of();
        int sum = 0;
        countDataDTO.appendLegend("心理评分");
        countDataDTO.appendLegend("疼痛评分");
        countDataDTO.appendLegend("营养评分");
        if (CollectionUtil.isEmpty(userProcessDataDTOList)) {
            countDataDTO.setScoreAvg(0);
            return countDataDTO;
        }
        for (UserProcessDataDTO userProcessDataDTO : userProcessDataDTOList) {
            if (!(userProcessDataDTO.getBaseProcessDataJson() instanceof ProcessFiveOfDataJson)) {
                continue;
            }
            ProcessFiveOfDataJson processDataJson = (ProcessFiveOfDataJson) userProcessDataDTO.getBaseProcessDataJson();
            countDataDTO.getXTypeList().add(userProcessDataDTO.getCreateDay());
            int score1 = Optional.ofNullable(processDataJson).map(ProcessFiveOfDataJson::getAnalysisOfMind).map(ItemRecordVO::getScore).orElse(0);
            int score2 = Optional.ofNullable(processDataJson).map(ProcessFiveOfDataJson::getAnalysisOfPain).map(ItemRecordVO::getScore).orElse(0);
            int score3 = Optional.ofNullable(processDataJson).map(ProcessFiveOfDataJson::getAnalysisOfNutrition).map(ItemRecordVO::getScore).orElse(0);
            countDataDTO.getSeriesList().get(0).getData().add(score1);
            countDataDTO.getSeriesList().get(1).getData().add(score2);
            countDataDTO.getSeriesList().get(2).getData().add(score3);
            sum += score1 + score2 + score3;
        }
        int nums = countDataDTO.getSeriesList().size() * countDataDTO.getSeriesList().get(0).getData().size();
        int scoreAvg = nums == 0 ? 0 : sum / nums;
        countDataDTO.setScoreAvg(scoreAvg);
        return countDataDTO;
    }


}
